iT邦幫忙

2024 iThome 鐵人賽

DAY 9
0
Software Development

輕鬆學習設計模式Design Pattern系列 第 9

Day 9 命令模式 Command Pattern

  • 分享至 

  • xImage
  •  

想像你正坐在一間高級餐廳裡。你不會直接走進廚房告訴廚師你想吃什麼,而是向服務生點餐。服務生記下你的要求,然後將其傳達給廚房。這個看似簡單的過程,其實蘊含了一個軟體設計概念,那就是命令模式 Command Pattern。今天我們就來聊聊這個讓程式碼更具彈性的設計模式。

什麼是命令模式?

命令模式是一種行為設計模式,它將一個請求封裝成一個物件,從而使你可以用不同的請求對客戶進行參數化。簡單來說,它就像是餐廳裡的點餐單,將"做什麼"與"誰來做"分離開來。

在軟體設計中,命令模式允許我們將一個操作(比如打開電燈)封裝成一個物件。這個物件包含了執行這個操作所需的所有資訊。這樣我們就可以在不知道操作具體內容或操作接收者的情況下,執行這個操作或者將其傳遞給其他程式碼。

命令模式通常包含以下幾個角色:

  1. Command(命令):定義了命令的介面,所有具體命令都必須實現這個介面。
  2. ConcreteCommand(具體命令):實現 Command 介面,將一個接收者物件綁定到一個動作。這樣當命令被呼叫時,對應的接收者就會執行相應的動作。
  3. Invoker(呼叫者):負責呼叫命令。
  4. Receiver(接收者):實際執行命令的邏輯或動作。

命令模式在智慧家庭中的應用

讓我們以智慧家庭的應用來解釋命令模式。假設你有一個智慧家庭系統,透過這個系統你可以控制家中的各種裝置,比如燈光、空調、音響等。當你想要打開燈光時,你不會去直接呼叫燈光的操作介面,而是透過智慧家庭系統發出一個命令來控制燈光的開關。這就是命令模式的典型應用。

首先我們定義一個 Command 介面,它包含一個 execute 方法,

// 命令介面 Command
class Command {
public:
    virtual void execute() = 0;
    virtual ~Command() = default;
};

接著我們為每一個裝置(如燈光)建立具體的命令類別,

// 接收者 Receiver
class Light {
public:
    void on() {
        std::cout << "Light is ON" << std::endl;
    }
    void off() {
        std::cout << "Light is OFF" << std::endl;
    }
};

// 具體命令 ConcreteCommand
class LightOnCommand : public Command {
private:
    Light* light;

public:
    LightOnCommand(Light* light) : light(light) {}

    void execute() override {
        light->on();
    }
};

class LightOffCommand : public Command {
private:
    Light* light;

public:
    LightOffCommand(Light* light) : light(light) {}

    void execute() override {
        light->off();
    }
};

接下來我們建立一個呼叫者類別,它含有一個命令物件,可以執行這個命令,

// 呼叫者 Invoker
class RemoteControl {
private:
    Command* command;

public:
    void setCommand(Command* command) {
        this->command = command;
    }

    void pressButton() {
        command->execute();
    }
};

現在當你想要開燈時,只需要透過命令模式來控制它,

int main() {
    Light* light = new Light();
    Command* lightOn = new LightOnCommand(light);
    Command* lightOff = new LightOffCommand(light);

    RemoteControl* remote = new RemoteControl();

    remote->setCommand(lightOn);
    remote->pressButton();  // 打開燈光

    remote->setCommand(lightOff);
    remote->pressButton();  // 關閉燈光

    delete light;
    delete lightOn;
    delete lightOff;
    delete remote;

    return 0;
}

這樣的設計讓我們可以輕鬆擴展新的裝置和命令,無需修改現有的程式碼。呼叫者完全不需要知道具體的裝置,只需呼叫對應的命令即可。

命令模式的優缺點

命令模式的優點在於它將請求的發送者和接收者解耦,使得系統更加靈活。就像我們的智能家居例子,遙控器(發送者)不需要知道是哪個裝置(接收者)在執行命令。這種解耦使得我們可以輕鬆地新增新的命令,而無需修改現有的程式碼。此外,命令模式還支援撤銷操作、讓操作可以被記錄、重做或者排程等進階功能,例如,你可以實現一個「撤銷」功能,只需將執行過的命令記錄下來,當需要撤銷時,呼叫相反的命令即可。

命令模式也有其缺點。由於每個具體命令都被封裝成一個單獨的類,它可能導致系統中的類數量暴增。這可能使得系統變得更加複雜,特別是當只有少量簡單命令時。其次,如果命令的執行涉及到大量的業務邏輯,那麼命令類可能變得臃腫,違反了單一職責原則。

總結

命令模式是一個強大且靈活的設計模式,能夠讓我們的程式設計更具組織性和可擴展性。雖然它可能會引入一些額外的複雜度,但在許多情境下,它所帶來的好處遠遠超過其缺點。在智慧家庭、遊戲開發以及企業級應用中,命令模式的應用無處不在。好的設計模式就像好的工具一樣,關鍵是要在適當的場景中恰當地使用它們。

更多C++語言相關的文章,歡迎追蹤我的部落格。
https://shengyu7697.github.io/cpp-command-pattern/


上一篇
Day 8 代理模式 Proxy Pattern
下一篇
Day 10 建造者模式 Builder Pattern
系列文
輕鬆學習設計模式Design Pattern30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言